// Tile.java
//
// Container for all the array positions in the game. Each tile
// holds information about the terrain, items, and mobs in that tile.

import java.util.ArrayList;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public class Tile
{
    // Instantiate the different things contained in a Tile
    // So far, this includes the Terrain of the tile, the
    // items laying in the tile, and the mobs present in
    // the tile (usually limited to one!).
    private Terrain terra;
    private ArrayList<Item> items;
    private ArrayList<Mob> mobs;
    private World world;
    
    // tx and ty are the tile's location (in relation to other tiles) passed from the World
    private int tx;
    private int ty;
    
    // whether or not mobs can pass through the tile
    private boolean passable;
    
    // An image to be overlaid on the tile, if it exists
    private Image overlay;

    public Tile(int terraNum, World passedWorld, int x, int y)
    {
        terra = new Terrain(terraNum);
        items = new ArrayList<Item>();
	mobs = new ArrayList<Mob>();
        tx = x;
	ty = y;
        world = passedWorld;
        if(terra.isPassable())
        {
            passable = true;
        }
        else
        {
            passable = false;
        }
    }

    // Main Methods

    // Displays all of the objects in the Tile in the correct order, at the passed coordinates
    public void display(int x, int y, Graphics g)
    {
        terra.display(x, y, g);
	for(Item i : items)
        {
            i.display(x, y, g);
        }
        for(Mob m : mobs)
        {
            m.display(x, y, g);
        }
        g.drawImage(overlay, x, y, null);
    }
    
    // Adds an overlay to the tile
    public void addOverlay(String s)
    {
        String file = "Overlays\\" + s + ".png";
        try
        {
            overlay = ImageIO.read(new File(file));
        }
        catch(IOException e)
        {
            System.out.println("Uh oh! Something broke with the file reading!");
            System.out.println(e);
        }
    }
    
    // remove an overlay
    public void clearOverlay()
    {
        overlay = null;
    }

    public void tick()
    {
        terra.tick();
        for(Item i : items)
        {
            i.tick();
        }
        for (Mob m : mobs)
        {
            m.tick();
        }
        
        // check to see whether the tile has become passable
        if((mobs.size() > 0) || !(terra.isPassable()))
        {
            passable = false;
        }
        else
        {
            passable = true;
        }
    }

    public void queue(Mob m)
    {
        world.queue(m);
    }
    
    // check to see whether the tile is passable
    public boolean isPassable()
    {
        return passable;
    }
    
    // get all tiles adjacent to this one
    public ArrayList<Tile> getSurroundingTiles()
    {
        Tile[][] l = world.getLandscape();
        ArrayList<Tile> t = new ArrayList<Tile>();
        
        //North
        if(world.isValid(tx, ty-1))
        {
            t.add(l[ty-1][tx]);
        }
        //Northeast
        if(world.isValid(tx+1, ty-1))
        {
            t.add(l[ty-1][tx+1]);
        }
        //East
        if(world.isValid(tx+1, ty))
        {
            t.add(l[ty][tx+1]);
        }
        //Southeast
        if(world.isValid(tx+1,ty+1))
        {
            t.add(l[ty+1][tx+1]);
        }
        //South
        if(world.isValid(tx, ty+1))
        {
            t.add(l[ty+1][tx]);
        }
        //Southwest
        if(world.isValid(tx-1, ty+1))
        {
            t.add(l[ty+1][tx-1]);
        }
        //West
        if(world.isValid(tx-1, ty))
        {
            t.add(l[ty][tx-1]);
        }
        //Northwest
        if(world.isValid(tx-1, ty-1))
        {
            t.add(l[ty-1][tx-1]);
        }
        return t;
    }
    
    // get tiles in radius i
    public ArrayList<Tile> getTilesInRadius(int r)
    {
        ArrayList<Tile> t = new ArrayList<Tile>();
        Tile[][] l = world.getLandscape();
        
        for (int i = r; i > 0; i--)
        {
            if (world.isValid(tx + i, ty))
            {
                t.add(l[ty][tx + i]);
            }
            if (world.isValid(tx - i, ty))
            {
                t.add(l[ty][tx - i]);
            }
            if (world.isValid(tx, ty + i))
            {
                t.add(l[ty + i][tx]);
            }
            if(world.isValid(tx, ty - i))
            {
                t.add(l[ty - i][tx]);
            }
            for (int y = (int) (r * Math.sin(Math.acos((double)i/r))); y >= 1; y--)
            {
                if (world.isValid(tx + i, ty + y))
                {
                    t.add(l[ty + y][tx + i]);
                }
                if (world.isValid(tx + i, ty - y))
                {
                    t.add(l[ty - y][tx + i]);
                }
                if (world.isValid(tx - i, ty + y))
                {
                    t.add(l[ty + y][tx - i]);
                }
                if (world.isValid(tx - i, ty -y))
                {
                    t.add(l[ty - y][tx - i]);
                }
            }
        }
        return t;
    }

    // Tile Gets/Sets

    // Returns x
    public int getX()
    {
        return tx;
    }

    // Returns y
    public int getY()
    {
        return ty;
    }

    // Item Methods

    // Adds a previously nonexisting item to the Tile
    public void addNewItem(int itemNum)
    {
        items.add(new Item(itemNum));
    }

    // Adds a previously existing item to the Tile
    public void addItem(Item newItem)
    {
        items.add(newItem);
    }

    // Removes an item from the Tile, given the item's index in the items list
    public void removeItem(int itemIndex)
    {
        items.remove(itemIndex);
    }

    // Returns an item from the Tile, given the item's index in the items list
    public Item getItem(int itemIndex)
    {
        return items.get(itemIndex);
    }

    // NOTE: Add remove and get based on item names and other values for convenience later

    // Returns an array with all of the ID numbers of the items in the Tile
    public int[] getItemNums()
    {
        int[] itemNums = new int[items.size()];
        for (int i = 0; i < items.size(); i++)
        {
            itemNums[i] = items.get(i).getNum();
        }
        return itemNums;
    }
    
    // Mob Methods

    // Adds a previously nonexisting mob to the Tile
    public void addNewMob(int mobNum)
    {
        mobs.add(new Mob(mobNum, this));
        passable = false;
    }

    // Adds a previously existing mob to the Tile
    public void addMob(Mob newMob)
    {
        mobs.add(newMob);
        passable = false;
    }

    // Removes a mob from the Tile, given the mob's index in the mobs list
    public void removeMob(int mobIndex)
    {
        mobs.remove(mobIndex);
    }

    // Returns a mob from the Tile, given the mob's index in the mobs list
    public Mob getMob(int mobIndex)
    {
        return mobs.get(mobIndex);
    }

    // NOTE: Again, add some more convenient methods if it become necessary

    // Returns an array with all of the ID numbers of the mobs in the Tile
    public int[] getMobNums()
    {
        int[] mobNums = new int[mobs.size()];
        for (int i = 0; i < mobs.size(); i++)
        {
            mobNums[i] = mobs.get(i).getNum();
        }
        return mobNums;
    }

    public void moveMobTo(int mobIndex, int x, int y)
    {
        world.getLandscape()[y][x].addMob(mobs.get(mobIndex));
        mobs.get(mobIndex).setTile(world.getLandscape()[y][x]);
	removeMob(mobIndex);
    }
    
    public void moveMobTo(int mobIndex, Tile t)
    {
        t.addMob(mobs.get(mobIndex));
        mobs.get(mobIndex).setTile(t);
        removeMob(mobIndex);
    }

    // Terrain Methods

    // Returns the terrain
    public Terrain getTerrain()
    {
        return terra;
    }

    // Sets the terrain to a different terrain, using the new terrain's ID number
    public void setTerrain(int newTerraNum)
    {
        terra = new Terrain(newTerraNum);
    }
    
    public String toString()
    {
        return "X: " + tx + ", Y: " + ty;
    }
 }